package com.example.tys.baseapplication.View.sufaceview;

import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.LinearGradient;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.PorterDuff;
import android.graphics.PorterDuffXfermode;
import android.graphics.Shader;
import android.graphics.Xfermode;
import android.util.AttributeSet;
import android.util.Log;
import android.view.SurfaceHolder;
import android.view.SurfaceView;

/**
 * Created by tys on 2017/11/8.
 */

public class Wave extends SurfaceView implements SurfaceHolder.Callback {
    private Path firstPath = new Path();
    private Path sencondPath = new Path();
    private Path centPath = new Path();
    private Xfermode mXfermode;
    private Paint mPaint;
    private float startTime;
    private LinearGradient shader;
    private int mWidth;
    private int mHeight;
    /**
     * 相位偏移
     */
    private double offset;
    /**
     * 采样个数
     */
    private int SAMPLE_COUNT = 128;
    /**
     * 采样点映射到5Pi范围类
     */
    private double SAMPLE_VAL = 1.6 * Math.PI / SAMPLE_COUNT;
    /**
     * 振幅
     */
    private int mAmplitude;
    /**
     * mWidth / SAMPLE_COUNT
     */
    private float gayX;
    /**
     * 绘制线程
     */
    private RenderThread renderThread;

    public Wave(Context context) {
        this(context, null);
    }

    public Wave(Context context, AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public Wave(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        init();
    }

    private void init() {
        getHolder().addCallback(this);
        mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
        mPaint.setDither(true);
        mPaint.setStrokeJoin(Paint.Join.ROUND);
        mPaint.setStrokeCap(Paint.Cap.ROUND);
        mPaint.setStrokeWidth(2);
        mXfermode = new PorterDuffXfermode(PorterDuff.Mode.SRC_IN);
        startTime = System.currentTimeMillis();
    }

    @Override
    public void surfaceCreated(SurfaceHolder holder) {
        renderThread = new RenderThread(holder);
        renderThread.start();
    }

    @Override
    public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
        mWidth = width;
        mHeight = height;
        mAmplitude = width >> 4;
        gayX = (float) mWidth / SAMPLE_COUNT;
        shader = new LinearGradient(0, -mAmplitude, 0, mAmplitude,
                new int[]{Color.BLUE, Color.GRAY}, null,
                Shader.TileMode.MIRROR);
    }

    @Override
    public void surfaceDestroyed(SurfaceHolder holder) {
        renderThread.setRunning(false);
    }

    private class RenderThread extends Thread {// 静态类部类，不持有外部类引用, 考虑弱引用,多个线程绘制时考虑资源锁
        private final SurfaceHolder mHolder;
        private boolean running = true;

        RenderThread(SurfaceHolder holder) {
            this.mHolder = holder;
        }

        void setRunning(boolean running) {
            this.running = running;
        }


        @Override
        public void run() {
            setName("wave view " + getId());
            while (true) {
                if (!running) {
                    break;
                }
                try {
                    Thread.sleep(16);
                    Canvas canvas = mHolder.lockCanvas();
                    if (canvas != null) {
                        render(canvas);
                        mHolder.unlockCanvasAndPost(canvas);
                    }
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
    }

    private void render(Canvas canvas) {
        canvas.drawRGB(255, 255, 255);
        canvas.translate(mWidth >> 1, mHeight >> 1); //坐标系原点为view的中心点
        float startPointX = -SAMPLE_COUNT / 2 * gayX;
        float startPointY = (float) calculate(-SAMPLE_COUNT / 2, 0);
        firstPath.rewind();
        sencondPath.rewind();
        centPath.rewind();
        firstPath.moveTo(startPointX, startPointY * mAmplitude);
        sencondPath.moveTo(startPointX, -startPointY * mAmplitude);
        centPath.moveTo(startPointX, startPointY * (mAmplitude >> 3));

        if (offset >= 2 * Math.PI || offset < 0) {
            offset = 0;
        } else {
            offset += 0.15; //相位步进
        }
        float currentY;
        for (int i = (-SAMPLE_COUNT >> 1) + 1; i <= SAMPLE_COUNT >> 1; i++) {
            currentY = (float) (calculate(i, offset));
//            if (Math.abs(currentY) ==0) {
//                Log.e("---", currentY + " : " + i);
//            }
            firstPath.lineTo(i * gayX, currentY * mAmplitude);
            sencondPath.lineTo(i * gayX, -currentY * mAmplitude);
            centPath.lineTo(i * gayX, currentY * (mAmplitude >> 2));
        }


        int saveLayer = canvas.saveLayerAlpha(-mWidth >> 1, -mAmplitude, mWidth >> 1, mAmplitude, 200, Canvas.ALL_SAVE_FLAG);//注意调用时机
        mPaint.setStyle(Paint.Style.STROKE);
        mPaint.setColor(Color.BLUE);
        canvas.drawPath(firstPath, mPaint);
//        canvas.drawPath(sencondPath, mPaint);
        mPaint.setColor(Color.RED);
        canvas.drawPath(centPath, mPaint);


//        mPaint.setShader(shader);
//        mPaint.setXfermode(mXfermode);
//        //整个区域画矩形，相邻的波峰波谷填充色一样
//        canvas.drawRect(-mWidth >> 1, -mAmplitude, mWidth >> 1, mAmplitude, mPaint);
//
//
//        mPaint.setXfermode(null);
//        mPaint.setShader(null);
//        canvas.restoreToCount(saveLayer);

        //描边
//        mPaint.setColor(Color.parseColor("#aeb8f5"));
//        mPaint.setStrokeWidth(3);
//        mPaint.setStyle(Paint.Style.STROKE);
//        canvas.drawPath(firstPath, mPaint);
//        canvas.drawPath(sencondPath, mPaint);
//        mPaint.setColor(Color.RED);
//        canvas.drawPath(centPath, mPaint);
    }

    /**
     * @param gay    第几个间隔 最小：-SAMPLE_COUNT/2 最大：SAMPLE_COUNT/2
     * @param offset 相位偏移
     * @return
     */
    private double calculate(double gay, double offset) {
        double x = SAMPLE_VAL * gay;//
        return Math.sin(0.6 * Math.PI * x - offset) * Math.pow(4 / (Math.pow(x, 4) + 4), 2.5);
    }


}
